#include <sys/mman.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/vfs.h>
#include <ustat.h>
#include <openssl/sha.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/wait.h>
#include <libaio.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/syscall.h>

#define DBG_SUBSYS S_LIBYLIB

#include "sysutil.h"
#include "dbg.h"

#define IO_MAX 2
#define IO_COUNT 1

int _test_aio()
{
        int ret, i, fd;
        io_context_t ctx;
        struct iocb *ioarray[IO_MAX], iocb[IO_MAX];
        struct io_event events[IO_MAX];
        char path[512], *buf;

        ctx = 0;
        ret = io_setup(IO_MAX, &ctx);
        if (ret < 0) {
                ret = -ret;
                printf("setup error %u\n", ret);
                GOTO(err_ret, ret);
        }

        sprintf(path, "/mnt/sda11/test");

        /*
        fd = mkstemp(path);
        if (fd < 0) {
                ret = errno;
                printf("mkstemp error %u\n", ret);
                GOTO(err_ret, ret);
        }
        */
        fd = open(path, O_RDWR|O_SYNC);
        if (fd < 0) {
                ret = errno;
                printf("open error %u\n", ret);
                GOTO(err_ret, ret);
        }

        //unlink(path);

        ret = posix_memalign((void *)&buf, PAGE_SIZE, PAGE_SIZE);
        if (unlikely(ret)) {
                printf("setup error %u\n", ret);
                GOTO(err_ret, ret);
        }

        strcpy(buf, "==========this is a test ==========");
        //io_prep_pwrite(&iocb[0], fd, buf, PAGE_SIZE, 0);
        //io_prep_pwrite(&iocb[1], fd, buf, PAGE_SIZE, 0);
        io_prep_fsync(&iocb[0], fd);

        for (i = 0; i < IO_MAX; i++) {
                ioarray[i] = &iocb[i];
        }

        ret = io_submit(ctx, IO_COUNT, ioarray);
        if (ret < 0) {
                ret = -ret;
                printf("submit error %u\n", ret);
                GOTO(err_close, ret);
        } else if (ret != IO_COUNT) {
                printf("submit %u, not enough\n", ret);
                GOTO(err_close, EPERM);
        }

        ret = io_getevents(ctx, IO_COUNT, IO_COUNT, events, NULL);
        if (ret < 0) {
                ret = -ret;
                printf("io_getevents error %u\n", ret);
                GOTO(err_close, ret);
        }

        printf("test ok\n");
        io_destroy(ctx);
        close(fd);

        return 0;
err_close:
        close(fd);
err_ret:
        return ret;
}

int _test_aio1()
{
        int ret, fd;
        io_context_t ctx;
        struct iocb *ioarray[1], iocb;
        struct io_event events;
        char path[512], *buf;

        ctx = 0;
        ret = io_setup(2, &ctx);
        if (ret < 0) {
                ret = -ret;
                printf("setup error %u\n", ret);
                GOTO(err_ret, ret);
        }

        sprintf(path, "/tmp/l-XXXXXX");

        fd = mkstemp(path);
        if (fd < 0) {
                ret = errno;
                printf("setup error %u\n", ret);
                GOTO(err_ret, ret);
        }

        unlink(path);

        ret = posix_memalign((void *)&buf, PAGE_SIZE, PAGE_SIZE);
        if (unlikely(ret)) {
                printf("setup error %u\n", ret);
                GOTO(err_ret, ret);
        }

        io_prep_pwrite(&iocb, fd, buf, PAGE_SIZE, 0);

        ioarray[0] = &iocb;
        ret = io_submit(ctx, 1, ioarray);
        if (ret != 1) {
                ret = -ret;
                printf("setup error %u\n", ret);
                GOTO(err_ret, ret);
        }

        ret = io_getevents(ctx, 1, 1, &events, NULL);
        if (ret < 0) {
                ret = -ret;
                printf("io_getevents error %u\n", ret);
                GOTO(err_ret, ret);
        }

        printf("test ok\n");
        io_destroy(ctx);

        return 0;
err_ret:
        return ret;
}

int unit_test_aio(const char *func)
{
        int ret;

        (void) func;
        ret = _test_aio();
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        return 0;
err_ret:
        return ret;
}
